/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * PinyinFrame.java
 *
 * Created on Jul 5, 2010, 4:48:11 PM
 */
package pinyin;

import pinyin.utils.Distance;
import pinyin.classifier.*;
import hmm.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * @author ray
 */
public class PinyinFrame extends javax.swing.JFrame {

//    PinyinToWord ptw = new PinyinToWord();
    SeqLabelClassifier<Character, String> ptw = new PinyinToWord();
    PinyinTokenizer tokenizer = new PinyinTokenizer("pinyin.dic");
//    WordToPinyin wtp = new WordToPinyin();
    SeqLabelClassifier<String, Character> wtp = new WordToPinyin();

    /** Creates new form PinyinFrame */
    public PinyinFrame() {
        initComponents();
        ptw.load("ptw.m");
        System.out.println("ptw load completed.");
        wtp.load("wtp.m");
        System.out.println("wtp load completed.");
        loadUserDict("userdict.txt");
        System.out.println("userdict load completed.");
        ptw.init();
        System.out.println("ptw init completed.");
        wtp.init();
        System.out.println("wtp init completed.");
        if (2 == Flag.n()) {
//            ptw.setN(2);
            ptw.setProperty("n", "2");
            rbBigram.setSelected(true);
            rbTrigram.setSelected(false);
            rbTrigram.enableInputMethods(false);
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        inputField = new javax.swing.JTextField();
        jScrollPane1 = new javax.swing.JScrollPane();
        outputArea = new javax.swing.JTextArea();
        rbBigram = new javax.swing.JRadioButton();
        rbTrigram = new javax.swing.JRadioButton();
        jCheckBox1 = new javax.swing.JCheckBox();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        inputField.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                inputFieldKeyReleased(evt);
            }
        });

        outputArea.setColumns(20);
        outputArea.setEditable(false);
        outputArea.setRows(5);
        jScrollPane1.setViewportView(outputArea);

        rbBigram.setText("bigram");
        rbBigram.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rbBigramActionPerformed(evt);
            }
        });

        rbTrigram.setSelected(true);
        rbTrigram.setText("trigram");
        rbTrigram.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rbTrigramActionPerformed(evt);
            }
        });

        jCheckBox1.setText("display all");
        jCheckBox1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jCheckBox1ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(rbBigram)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(rbTrigram)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jCheckBox1)
                .addContainerGap(144, Short.MAX_VALUE))
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
            .addComponent(inputField, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(rbBigram)
                    .addComponent(rbTrigram)
                    .addComponent(jCheckBox1))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(inputField, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 133, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void inputFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_inputFieldKeyReleased
        // TODO add your handling code here:
        char ch = evt.getKeyChar();

        boolean isPinyin = true;
        isPinyin = !inputField.getText().matches(".*[一-龥].*");
        if (0x0A == ch) {
            outputArea.setText("");

            if (isPinyin) {
                pinyinToWord();
            } else {
                wordToPinyin();
            }
        } else {
            if (isPinyin && Character.isLetter(ch)) {
                String[] o = tokenizer.tokenize(inputField.getText().replaceAll("'", "").trim());
                if (o.length > 0) {
                    StringBuilder sb = new StringBuilder();
                    for (String s : o) {
                        sb.append(s).append("'");
                    }
                    sb.deleteCharAt(sb.length() - 1);
                    int p = inputField.getCaretPosition();
                    int l = inputField.getText().length();
                    inputField.setText(sb.toString());
                    inputField.setCaretPosition(p + sb.length() - l);
                }
            }
        }
    }//GEN-LAST:event_inputFieldKeyReleased

    private void rbTrigramActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rbTrigramActionPerformed
        // TODO add your handling code here:
        ptw.setProperty("n", "3");
        rbBigram.setSelected(false);
    }//GEN-LAST:event_rbTrigramActionPerformed

    private void rbBigramActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rbBigramActionPerformed
        // TODO add your handling code here:
        ptw.setProperty("n", "2");
        rbTrigram.setSelected(false);
    }//GEN-LAST:event_rbBigramActionPerformed

    private void jCheckBox1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBox1ActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_jCheckBox1ActionPerformed

    private String correct(String pinyin, String txt) {
        String ret = null;
        String[] o = tokenizer.tokenize(pinyin);
        List<Character> res = null;
        try {
            res = ptw.classify(Arrays.asList(o));
        } catch (RuntimeException ex) {
            System.out.println(ex.getMessage());
        }
        String str = "";
        if (null != res) {
            for (Character state : res) {
                str += state;
            }

            Distance dis = new Distance();
            int n = dis.LD(str, txt);
            if (n == 1) {
                ret = str;
            }
        }
        return ret;
    }

    private void pinyinToWord() {
        String[] o = tokenizer.tokenize(inputField.getText().trim());

        Result ret = null;
        try {
            ret = ptw.labelStateOfNodes(Arrays.asList(o));
        } catch (RuntimeException ex) {
            System.out.println(ex.getMessage());
        }
        Map<Double, String> results = new HashMap<Double, String>();
        if (null != ret && ret.states() != null) {
            for (int pos = 0; pos < ret.states()[o.length - 1].length; pos++) {
                StringBuilder sb = new StringBuilder();
                int[] statePath = Viterbi.getStatePath(ret.states(), ret.psai(), o.length - 1, o.length, pos);
                for (int stateId : statePath) {
                    Character name = ptw.getStateBy(stateId);
                    sb.append(name).append(" ");
                }
                sb.append(Double.toString(ret.delta()[o.length - 1][pos]));
                results.put(ret.delta()[o.length - 1][pos], sb.toString());
            }
            List<Double> list = new ArrayList<Double>(results.keySet());
            Collections.sort(list);
            Collections.reverse(list);
            int end = jCheckBox1.isSelected()
                    ? ret.states()[o.length - 1].length
                    : ret.states()[o.length - 1].length >= 7 ? 7 : ret.states()[o.length - 1].length;
            int i = 0;
            for (Double d : list) {
                outputArea.append(results.get(d));
                outputArea.append("\n");
                if (++i >= end) {
                    break;
                }
            }
        }
    }

    private void wordToPinyin() {
        String txt = inputField.getText().replaceAll("[\\w\\d\\s\\pP~]+", "");
        char[] chs = txt.toCharArray();
        Character[] o = new Character[chs.length];
        for(int i = 0; i < chs.length; i++){
            o[i] = chs[i];
        }

        Result ret = null;
        try {
            ret = wtp.labelStateOfNodes(Arrays.asList(o));
        } catch (RuntimeException ex) {
            System.out.println(ex.getMessage());
        }
        Map<Double, String> results = new HashMap<Double, String>();
        if (null != ret && ret.states() != null) {
            for (int pos = 0; pos < ret.states()[o.length - 1].length; pos++) {
                StringBuilder sb = new StringBuilder();
                int[] statePath = Viterbi.getStatePath(ret.states(), ret.psai(), o.length - 1, o.length, pos);
                for (int stateid : statePath) {
                    String name = wtp.getStateBy(stateid);
                    sb.append(name).append(" ");
                }
                sb.append(Double.toString(ret.delta()[o.length - 1][pos]));
                results.put(ret.delta()[o.length - 1][pos], sb.toString());
            }
            List<Double> list = new ArrayList<Double>(results.keySet());
            Collections.sort(list);
            Collections.reverse(list);

            String pinyin = results.get(list.get(0)).replaceAll("[-\\d\\.]+", "").trim();
            String correct = correct(pinyin, txt);


            if (null != correct) {
                outputArea.append(correct);
                outputArea.append("\n");
            }

            int end = jCheckBox1.isSelected()
                    ? ret.states()[o.length - 1].length
                    : ret.states()[o.length - 1].length >= 7 ? 7 : ret.states()[o.length - 1].length;
            int i = 0;
            for (Double d : list) {
                outputArea.append(results.get(d));
                outputArea.append("\n");
                if (++i >= end) {
                    break;
                }
            }
        }
    }

    public void loadUserDict(String filename) {
//        File file = new File(filename);
//        InputStream is = null;
//        try {
//            if (file.exists()) {
//                is = new FileInputStream(file);
//            } else {
//                is = PinyinFrame.class.getClassLoader().getResourceAsStream(filename);
//                if (null == is) {
//                    return;
//                }
//            }
//            BufferedReader br = new BufferedReader(
//                    new InputStreamReader(is, "UTF-8"));
//            String line = br.readLine();
//
//            while (null != line) {
//                line = line.trim();
//                if (!"".equals(line)) {
//                    String[] array = line.split("\\s+");
//                    int showtimes = array.length > 2 ? Integer.valueOf(array[2]) : 50;
//                    ptw.addCustomWord(array[0], array[1], showtimes);
//                }
//                line = br.readLine();
//            }
//            br.close();
//        } catch (IOException ex) {
//            ex.printStackTrace();
//        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new PinyinFrame().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTextField inputField;
    private javax.swing.JCheckBox jCheckBox1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextArea outputArea;
    private javax.swing.JRadioButton rbBigram;
    private javax.swing.JRadioButton rbTrigram;
    // End of variables declaration//GEN-END:variables
}
